﻿using QMesSocketLib;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Windows.Forms;

namespace QMesSocketClient
{
    /// <summary>
    /// 附件管理
    /// </summary>
    public partial class FormAttachments : Form
    {
        static string ip = "127.0.0.1";
        int port = 9002;
        static string currentPath = Environment.CurrentDirectory;
        public string FormName { get; set; }
        public string BillNo { get; set; }
        public bool IsReadOnly { get; set; }
        List<FileEntity> _Files = new List<FileEntity>();
        int BufferSize = 1000000;
        int Max = 5;
        int _ReceiveTimeout = 30000;
        int _SnedTimeout = 30000;

        public string FileName { get; set; }

        List<string> tempFileList = new List<string>();

        /// <summary>
        /// 附件管理
        /// </summary>
        /// <param name="formName">程序代号</param>
        /// <param name="billNo">单号</param>
        /// <param name="serverAddress">附件服务器地址</param>
        /// <param name="serverPort">附件服务器端口</param>
        /// <param name="max">附件最大值</param>
        public FormAttachments(string formName, string billNo, string serverAddress, int serverPort, int max, bool isReadOnly)
        {
            InitializeComponent();

            try
            {
                this.FormName = formName;
                this.BillNo = billNo;
                this.Text = this.Text + "  " + billNo;

                if (!string.IsNullOrWhiteSpace(serverAddress)) ip = serverAddress;
                if (serverPort > 0) port = serverPort;
                if (Max > 0) Max = max;
                IsReadOnly = isReadOnly;
                if (string.IsNullOrWhiteSpace(this.FormName)) this.FormName = "DEBUG";
                dataGridView1.AutoGenerateColumns = false;
            }
            catch (Exception ex)
            {
                Log.LogError(ex);
            }
        }

        //选文件
        private void btnFileSelect_Click(object sender, EventArgs e)
        {
            try
            {
                OpenFileDialog f = new OpenFileDialog();
                f.Filter = "Excel|*.xlsx;*.xls|Word|*.docx;*.doc|图片|*.png;*.jpg;*.bmp;*.gif|PDF|*.pdf|文本文件|*.txt|压缩文件|*.zip;*.rar";
                if (f.ShowDialog() == DialogResult.OK)
                    txtFileName.Text = f.FileName;
                else
                    txtFileName.Text = string.Empty;
            }
            catch (Exception ex)
            {
                Log.LogError(ex);
            }
        }

        BackgroundWorker workerUpload = null;
        private void btnUpload_Click(object sender, EventArgs e)
        {

            if (string.IsNullOrWhiteSpace(txtFileName.Text))
            {
                MessageBox.Show("请先选择要上传的文件！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            if (!File.Exists(txtFileName.Text))
            {
                MessageBox.Show(string.Format("文件【{0}】不存在！", txtFileName.Text)
                    , "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            Socket sock = null;
            string path = txtFileName.Text;
            //if (workerUpload == null)
            {
                workerUpload = new BackgroundWorker();
                workerUpload.DoWork += (s, a) =>
                {
                    try
                    {
                        sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                        sock.Connect(new IPEndPoint(IPAddress.Parse(ip), port));

                        try
                        {
                            using (FileStream reader = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.None))
                            {
                                long send = 0L, length = reader.Length;


                                if (Max > 0 && length > Max * 1000000)
                                    throw new Exception("文件太大，文件大小限制为：" + Max.ToString() + "M");

                                MessageEntity msg = new MessageEntity();
                                msg.FormName = this.FormName;
                                msg.BillNo = this.BillNo;
                                msg.File.FileName = Path.GetFileName(path);
                                msg.File.FileFullName = path;
                                msg.File.FileLength = length;
                                msg.Type = EnumLib.SocketType.Upload;

                                string sendStr = msg.ToJson();

                                string fileName = Path.GetFileName(path);
                                sock.Send(Encoding.Default.GetBytes(sendStr));


                                byte[] buffer = new byte[BufferSize];
                                sock.Receive(buffer);
                                string receiveStr = Encoding.Default.GetString(buffer);

                                MessageEntity receiveMsg = receiveStr.ToObject<MessageEntity>();
                                if (receiveMsg == null)
                                {
                                    string error = string.Format("字符串 {0} 无法转换为消息实体", receiveStr);
                                    Log.LogMessage(error);
                                    return;
                                }

                                if (receiveMsg.Type == EnumLib.SocketType.ReadyToSendFile)
                                {
                                    byte[] fileBuffer = new byte[BufferSize];
                                    int read, sent;
                                    while ((read = reader.Read(fileBuffer, 0, BufferSize)) != 0)
                                    {
                                        sent = 0;
                                        while ((sent += sock.Send(fileBuffer, sent, read, SocketFlags.None)) < read)
                                        {
                                            send += (long)sent;
                                        }
                                    }

                                    reader.Close();
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            Log.LogError(ex);
                            throw ex;
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.LogError(ex);
                        throw ex;
                    }
                };
                workerUpload.RunWorkerCompleted += (s, a) =>
                {
                    try
                    {
                        if (a.Error != null)
                            tssMessage.Text = a.Error.Message;
                        if (sock != null)
                        {
                            sock.Close();
                        }

                        if (a.Error == null)
                        {
                            this.FileName = Path.GetFileName(txtFileName.Text);
                            txtFileName.Text = string.Empty;
                            tssMessage.Text = "上传完成!";
                            GetFileList();
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.LogError(ex);
                        tssMessage.Text = ex.Message;
                    }
                };
            }
            //else
            //{
            //    if (workerUpload.IsBusy) return;
            //}

            workerUpload.RunWorkerAsync();
        }

        BackgroundWorker workerDownload = null;
        private void btnDownLoad_Click(object sender, EventArgs e)
        {
            try
            {
                if (dataGridView1.Rows.Count == 0) return;
                if (dataGridView1.CurrentRow == null)
                {
                    MessageBox.Show("请选择文件行", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return;
                }

                FileEntity selectFile = dataGridView1.CurrentRow.DataBoundItem as FileEntity;
                if (selectFile == null) return;
                Download(selectFile.FileName);
            }
            catch (Exception ex)
            {
                Log.LogError(ex);
            }
        }

        /// <summary>
        /// 下载并打开文件
        /// </summary>
        /// <param name="fileName"></param>
        public void Download(string fileName)
        {
            string tempPath = currentPath + "\\" + "temp";
            if (!Directory.Exists(tempPath))
                Directory.CreateDirectory(tempPath);

            string tempFileName = Path.Combine(tempPath, fileName);

            Socket sock = null;
            //if (workerDownload == null)
            {
                workerDownload = new BackgroundWorker();
                workerDownload.DoWork += (s, a) =>
                {

                    try
                    {
                        sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                        sock.Connect(new IPEndPoint(IPAddress.Parse(ip), port));

                        try
                        {
                            MessageEntity msg = new MessageEntity();
                            msg.FormName = this.FormName;
                            msg.BillNo = this.BillNo;
                            msg.File.FileName = fileName;
                            //msg.File.FileFullName = path;
                            msg.Type = EnumLib.SocketType.DownLoad;
                            sock.Send(Encoding.Default.GetBytes(msg.ToJson()));

                            byte[] buffer = new byte[BufferSize];
                            sock.Receive(buffer);

                            string receiveStr = Encoding.Default.GetString(buffer);
                            MessageEntity receiveMsg = receiveStr.ToObject<MessageEntity>();
                            if (receiveMsg == null)
                            {
                                string error = string.Format("字符串 {0} 无法转换为消息实体", receiveStr);
                                Log.LogMessage(error);
                                return;
                            }


                            long receive = 0L;
                            if (receiveMsg.Type == EnumLib.SocketType.ReadyToSendFile)
                            {
                                using (FileStream writer = new FileStream(tempFileName, FileMode.Create, FileAccess.Write, FileShare.None))
                                {
                                    int received;
                                    while (receive < receiveMsg.File.FileLength)
                                    {
                                        received = sock.Receive(buffer);
                                        writer.Write(buffer, 0, received);
                                        writer.Flush();
                                        receive += (long)received;
                                    }
                                    writer.Close();
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            Log.LogError(ex);
                            throw ex;
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.LogError(ex);
                        throw ex;
                    }
                };
                workerDownload.RunWorkerCompleted += (s, a) =>
                {
                    try
                    {
                        if (sock != null) sock.Close();
                    }
                    catch (Exception ex)
                    {
                        Log.LogError(ex);
                    }
                    if (File.Exists(tempFileName))
                    {
                        tempFileList.Add(tempFileName);
                        System.Diagnostics.Process.Start(tempFileName);
                    }
                };
            }


            workerDownload.RunWorkerAsync();
        }

        /// <summary>
        /// 下载多个文件
        /// </summary>
        /// <param name="fileList"></param>
        public void DownloadFiles(List<FileEntity> fileList)
        {
            string tempPath = currentPath + "\\" + "temp";
            if (!Directory.Exists(tempPath))
                Directory.CreateDirectory(tempPath);

            

            try
            {
                foreach (FileEntity fileEntity in fileList)
                {
                    Socket sock = null;
                    try
                    {
                        //建立连接
                        sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                        sock.Connect(new IPEndPoint(IPAddress.Parse(ip), port));

                        //发送下载请求
                        MessageEntity msg = new MessageEntity();
                        msg.FormName = this.FormName;
                        msg.BillNo = this.BillNo;
                        msg.File.FileName = fileEntity.FileName;
                        msg.File.FileFullName = Path.Combine(tempPath, fileEntity.FileName);
                        fileEntity.FileFullName = msg.File.FileFullName;
                        msg.Type = EnumLib.SocketType.DownLoad;
                        sock.Send(Encoding.Default.GetBytes(msg.ToJson()));

                        //接收回复
                        byte[] buffer = new byte[BufferSize];
                        sock.Receive(buffer);
                        string receiveStr = Encoding.Default.GetString(buffer);
                        MessageEntity receiveMsg = receiveStr.ToObject<MessageEntity>();
                        if (receiveMsg == null)
                        {
                            string error = string.Format("字符串 {0} 无法转换为消息实体", receiveStr);
                            Log.LogMessage(error);
                            return;
                        }

                        //开始下载
                        long receive = 0L;
                        if (receiveMsg.Type == EnumLib.SocketType.ReadyToSendFile)
                        {
                            using (FileStream writer = new FileStream(msg.File.FileFullName, FileMode.Create, FileAccess.Write, FileShare.None))
                            {
                                int received;
                                while (receive < receiveMsg.File.FileLength)
                                {
                                    received = sock.Receive(buffer);
                                    writer.Write(buffer, 0, received);
                                    writer.Flush();
                                    receive += (long)received;
                                }
                                writer.Close();
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.LogError(ex);
                        throw ex;
                    }
                    finally
                    {
                        if (sock != null)
                        {
                            try
                            {
                                sock.Close();
                            }
                            catch { }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Log.LogError(ex);
                throw ex;
            }
        }

        BackgroundWorker workerFileList = null;
        void GetFileList()
        {
            if (string.IsNullOrWhiteSpace(this.FormName)) return;

            Socket sock = null;

            //if (workerFileList == null)
            {
                workerFileList = new BackgroundWorker();
                workerFileList.DoWork += (s, a) =>
                {
                    _Files = GetFilesList();
                    if (_Files == null) _Files = new List<FileEntity>();
                    #region
                    /*
                    try
                    {
                        sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                        sock.Connect(new IPEndPoint(IPAddress.Parse(ip), port));

                        string path = txtFileName.Text;
                        try
                        {
                            //发送请求
                            MessageEntity msg = new MessageEntity();
                            msg.FormName = this.FormName;
                            msg.BillNo = this.BillNo;
                            msg.Type = EnumLib.SocketType.FileList;
                            sock.Send(Encoding.Default.GetBytes(msg.ToJson()));

                            //接收
                            byte[] buffer = new byte[BufferSize];
                            sock.Receive(buffer);
                            string receiveStr = Encoding.Default.GetString(buffer);
                            List<FileEntity> list = receiveStr.ToObject<List<FileEntity>>();
                            if (list == null)
                            {
                                string error = string.Format("字符串 {0} 无法转换为文件列表", receiveStr);
                                Log.LogMessage(error);
                                return;
                            }
                            else
                            {
                                _Files = list;
                            }
                        }
                        catch (Exception ex)
                        {
                            _Files.Clear();
                            Log.LogError(ex);
                            throw ex;
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.LogError(ex);
                        throw ex;
                    }
                    */
                    #endregion
                };

                workerFileList.RunWorkerCompleted += (s, a) =>
                 {
                     try
                     {
                         if (a.Error != null)
                             tssMessage.Text = a.Error.Message;

                         if (sock != null)
                         {
                             sock.Close();
                         }

                         dataGridView1.DataSource = new BindingList<FileEntity>(_Files);
                         tssCount.Text = _Files.Count.ToString();
                     }
                     catch (Exception ex)
                     {
                         Log.LogError(ex);
                         tssMessage.Text = ex.Message + " " + tssMessage.Text;
                     }
                 };
            }
            //else
            //{
            //    if (workerFileList.IsBusy) return;
            //}

            workerFileList.RunWorkerAsync();
        }

        /// <summary>
        /// 获取指定单据下的所有文件的实体
        /// </summary>
        /// <returns></returns>
        public List<FileEntity> GetFilesList()
        {
            List<FileEntity> list = null;
            if (string.IsNullOrWhiteSpace(this.FormName)) return null;

            Socket sock = null;

            try
            {
                sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                sock.Connect(new IPEndPoint(IPAddress.Parse(ip), port));

                string path = txtFileName.Text;
                try
                {
                    //发送请求
                    MessageEntity msg = new MessageEntity();
                    msg.FormName = this.FormName;
                    msg.BillNo = this.BillNo;
                    msg.Type = EnumLib.SocketType.FileList;
                    sock.Send(Encoding.Default.GetBytes(msg.ToJson()));

                    //接收
                    byte[] buffer = new byte[BufferSize];
                    sock.ReceiveTimeout = _ReceiveTimeout;
                    sock.Receive(buffer);
                    string receiveStr = Encoding.Default.GetString(buffer);
                    list = receiveStr.ToObject<List<FileEntity>>();
                }
                catch (Exception ex)
                {
                    _Files.Clear();
                    Log.LogError(ex);
                    throw ex;
                }
            }
            catch (Exception ex)
            {
                Log.LogError(ex);
                throw ex;
            }
            finally
            {
                if(sock != null)
                {
                    try
                    {
                        sock.Close();
                    }
                    catch { }
                }
            }

            return list;
        }
    

        private void tsmOpen_Click(object sender, EventArgs e)
        {
            btnDownLoad_Click(btnDownLoad,new EventArgs());
        }

        private void FormAttachments_Shown(object sender, EventArgs e)
        {
            if(IsReadOnly)
            {
                tsmDelete.Enabled = false;
                btnUpload.Enabled = false;
                btnFileSelect.Enabled = false;
            }
        }

        bool IsLoad = false;
        private void FormAttachments_Load(object sender, EventArgs e)
        {
            if(!IsLoad) GetFileList();
            IsLoad = true;
        }

        private void tsmRefresh_Click(object sender, EventArgs e)
        {
            GetFileList();
        }

        BackgroundWorker workerDel = null;
        private void tsmDelete_Click(object sender, EventArgs e)
        {
            if (dataGridView1.Rows.Count == 0) return;
            if (dataGridView1.CurrentRow == null)
            {
                MessageBox.Show("请选择要删除的文件行", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            FileEntity selectFile = dataGridView1.CurrentRow.DataBoundItem as FileEntity;
            if (selectFile == null) return;
            string fileName = selectFile.FileName;

            if (MessageBox.Show("即将删除文件：" + selectFile.FileName + ", 删除后无法恢复，请确认！"
                , "请确认", MessageBoxButtons.OKCancel, MessageBoxIcon.Question)
                == DialogResult.Cancel)
            {
                return;
            }

            Socket sock = null;
            //if (workerDel == null)
            {
                workerDel = new BackgroundWorker();
                workerDel.DoWork += (s, a) =>
                 {
                     sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                     sock.Connect(new IPEndPoint(IPAddress.Parse(ip), port));
                     MessageEntity msg = new MessageEntity();
                     msg.FormName = this.FormName;
                     msg.BillNo = this.BillNo;
                     msg.File.FileName = fileName;
                     msg.Type = EnumLib.SocketType.Delete;
                     sock.Send(Encoding.Default.GetBytes(msg.ToJson()));
                 };
                workerDel.RunWorkerCompleted += (s, a) =>
                {
                    try
                    {
                        if (sock != null) sock.Close();
                    }
                    catch(Exception ex)
                    {
                        Log.LogError(ex);
                    }
                    if (a.Error == null)
                    {
                        tssMessage.Text = "已删除文件：" + selectFile.FileName;
                        GetFileList();
                    }
                };
            }
            //else
            //{
            //    if (workerDel.IsBusy) return;
            //}

            workerDel.RunWorkerAsync();
        }

        private void FormAttachments_FormClosing(object sender, FormClosingEventArgs e)
        {
            if(tempFileList.Count>0)
            {
                foreach(string f in tempFileList)
                {
                    try
                    {
                        if(File.Exists(f))
                            File.Delete(f);
                    }
                    catch(Exception ex)
                    {

                    }
                }
            }
        }

        private void tsmExit_Click(object sender, EventArgs e)
        {
            this.Close();
        }
    }
}
